package com.stenio.fancat.service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.stenio.fancat.domain.User;
import com.stenio.fancat.domain.UserAccount;
import com.stenio.fancat.exception.FanCatException;
import com.stenio.fancat.exception.SendSmsErrorException;
import com.stenio.fancat.form.LoginForm;
import com.stenio.fancat.mapper.UserAccountMapper;
import com.stenio.fancat.mapper.UserMapper;
import com.stenio.fancat.util.JsonUtil;
import com.stenio.fancat.util.SmsUtil;
import com.stenio.fancat.util.StringUtil;
import com.stenio.fancat.vo.LoginVO;

/**
 * 登录模块服务实现类
 *
 */
@Service
public class LoginService {

	public static final String SMS_CODE_PREFIX = "sms_code_";
	public static final String SESSION_PREFIX = "session_";
	@Autowired
	private SmsUtil smsUtil;
	@Autowired
	private StringRedisTemplate redis;
	@Autowired
	private UserMapper userMapper;
	@Autowired
	private UserAccountMapper userAccountMapper;

	public void getSmsCode(String phoneNumber) throws FanCatException {
		String code = StringUtil.getRandomNumber(4);
		Map<String, String> params = new HashMap<>();
		params.put("code", code);
		try {
			smsUtil.send(phoneNumber, "SMS_135800460", params);
			redis.opsForValue().set(getSmsCodeKey(phoneNumber), code, 5, TimeUnit.MINUTES);
		} catch (SendSmsErrorException e) {
			throw new FanCatException(e.getMessage());
		}
	}

	@Transactional
	public LoginVO login(LoginForm form) throws FanCatException {
		if (null == form || StringUtils.isBlank(form.getPhone())) {
			throw new RuntimeException("手机号不能为空");
		}
		if (!StringUtil.isMobile(form.getPhone()))
			throw new RuntimeException("手机号格式有误");
		if (validate(form.getPhone(), form.getSmsCode())) {
			User u = getUser(form.getPhone());
			if (u == null) {
				u = new User();
				u.setPhone(form.getPhone());
				u.setNikeName(form.getPhone());
				u.setUserName(form.getPhone());
				userMapper.insertSelective(u);
				UserAccount userAccount = new UserAccount();
				userAccount.setUserId(u.getUserId());
				userAccountMapper.insert(userAccount);
			}
			delete(form.getPhone());
			String sessionId = StringUtil.getUUID();
			redis.opsForValue().set(SESSION_PREFIX + sessionId, JsonUtil.toJson(u), 7, TimeUnit.DAYS);
			LoginVO v = new LoginVO();
			v.setUserId(u.getUserId().toString());
			v.setSessionId(sessionId);
			return v;
		} else {
			throw new FanCatException("验证码错误");
		}
	}

	/**
	 * 等三方微信登录
	 * 
	 * @param form
	 *            微信唯一标识（form.unionId）
	 * @return
	 * @throws FanCatException
	 */
	@Transactional
	public LoginVO thirdLogin(LoginForm form) {
		if (null != form && StringUtils.isNotBlank(form.getUnionId())) {
			String unionId = form.getUnionId();
			User u = new User();
			u.setUnionId(unionId);
			u = userMapper.selectOne(u);
			// 用户不存在需要创建用户及账号
			if (null == u || null == u.getUserId()) {
				u = new User();
				u.setNikeName(unionId);
				u.setUserName(unionId);
				u.setUnionId(unionId);
				userMapper.insertSelective(u);
				UserAccount userAccount = new UserAccount();
				userAccount.setUserId(u.getUserId());
				userAccountMapper.insert(userAccount);
			}
			// 将用户信息保存到redis中，k=sessionid，v=user
			String sessionId = StringUtil.getUUID();
			redis.opsForValue().set(SESSION_PREFIX + sessionId, JsonUtil.toJson(u), 7, TimeUnit.DAYS);
			LoginVO v = new LoginVO();
			v.setUserId(u.getUserId().toString());
			v.setSessionId(sessionId);
			return v;
		} else {
			throw new RuntimeException("第三方登录参数有误");
		}
	}

	// private void saveUser(User u) {
	// userMapper.insert(u);
	// }

	public boolean validate(String phone, String code) {
		String codeDB = redis.opsForValue().get(getSmsCodeKey(phone));
		if (codeDB != null && codeDB.equals(code)) {
			return true;
		}
		return false;
	}

	public void delete(String phone) {
		redis.delete(getSmsCodeKey(phone));
	}

	private String getSmsCodeKey(String phone) {
		return SMS_CODE_PREFIX + phone;
	}

	public User getUser(String phone) {
		User u = new User();
		u.setPhone(phone);
		return userMapper.selectOne(u);
	}
}
